package com.vordel.example.filter.simple;

import java.io.ByteArrayInputStream;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.vordel.circuit.Circuit;
import com.vordel.circuit.CircuitAbortException;
import com.vordel.circuit.CircuitInvocation;
import com.vordel.circuit.FilterConfigureContext;
import com.vordel.circuit.Message;
import com.vordel.circuit.MessageProcessor;
import com.vordel.circuit.MessageProperties;
import com.vordel.dwe.ByteArrayContentSource;
import com.vordel.es.EntityStoreException;
import com.vordel.mime.Body;
import com.vordel.mime.HeaderSet;
import com.vordel.mime.XMLBody;

/**
 * This object acts as a simple "Addition" Web Service
 * The processor will examine the incoming XML message and will look
 * for two parameters in the message and then will add the two
 * values togetther and set the message to be the result of the
 * calculation
 *
 * The incoming message is expected to be in the following format:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Add xmlns="http://startvbdotnet.com/web/">
      <a>1</a>
      <b>1</b>
    </Add>
  </soap:Body>
</soap:Envelope>

 The SimpleFilter will contain the local name of the two parameters (i.e. a and b)
 and will also contain the namespace that these elements belong to (i.e. http://startvbdotnet.com/web/)
 */
public class Processor extends MessageProcessor {

    // fragment of the hardcoded response for client (start of the XML response)
    private static final String RESPONSE_START =
        "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
        "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""  +
        " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
        "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n" +
        "<soap:Body><AddResponse xmlns=\"http://startvbdotnet.com/web/\">\n" +
        "<AddResult>";
    // fragment of the hardcoded response for client (end of the XML response)
    private static final String RESPONSE_END =
        "</AddResult></AddResponse></soap:Body></soap:Envelope>";

    @Override
    public void filterAttached(FilterConfigureContext ctx, com.vordel.es.Entity entity) throws EntityStoreException {
        // nothing to do here for initialisation
        super.filterAttached(ctx, entity);
    }

    /**
     * The invoke method. This method performs the filter processing.
     * @param c The circuit
     * @param message The message
     * @return true or false.
     */
    public boolean invoke(CircuitInvocation c, Message message)
    throws CircuitAbortException {

        // get the incoming request message as a DOM
        Document doc = getDOM(message);

        // default result
        String result = "UNKNOWN";

        // cast the filter member variable to the SiteMinderFilter so that we
        // may get access to the some details store here, i.e parameter names etc.
        Filter f = (Filter)getFilter();

        // look into the DOM to get the two parameters
        // get the first parameter
        NodeList parma1 =
            doc.getElementsByTagNameNS(f.param1Namespace, f.param1);
        if (parma1 == null || parma1.getLength() <= 0)
            throw new CircuitAbortException("Could not find " +
                    f.param1 + "in message");
        // get the value passed in the first parameter
        String a = getElementContent((Element)parma1.item(0));
        // get the second parameter
        NodeList parma2 =
            doc.getElementsByTagNameNS(f.param2Namespace, f.param2);
        if (parma2 == null || parma2.getLength() <= 0)
            throw new CircuitAbortException("Could not find " +
                    f.param2 + "in message");
        // get the value of the second parameter
        String b = getElementContent((Element)parma2.item(0));

        // work out the actual result based on the two parameters
        result = Integer.toString(Integer.parseInt(a) +
                Integer.parseInt(b));

        // set the response by setting the content body to be the
        // response
        StringBuffer response = new StringBuffer(RESPONSE_START);
        response.append(result);
        response.append(RESPONSE_END);
        Body convertedBody =
            Body.create(new HeaderSet(), Body.CT_TEXT_XML_UTF8,
                    new ByteArrayContentSource(response.toString().getBytes()));
        message.put(MessageProperties.CONTENT_BODY,
                convertedBody);

        return true;
    }

    /**
     * Utility for get the DOM from the message
     */
    protected Document getDOM(Message message)
    throws CircuitAbortException
    {
        try {
            return XMLBody.getDocument(message);
        } catch (java.io.IOException e) {
            throw new CircuitAbortException(e);
        }
    }

    /**
     * Utility for getting the actual content of an element
     */
    public static String getElementContent(Element element) {
        StringBuffer content = new StringBuffer();
        NodeList children = element.getChildNodes();
        for (int i=0; i<children.getLength(); i++) {
            Node node = children.item(i);
            if (node.getNodeType() == Node.TEXT_NODE) {
                content.append(node.getNodeValue());
            }
        }
        return content.toString().trim();
    }
}
